package com.java.simple.study.juc.p5;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.IntUnaryOperator;

/**
 * @author zhoujunlin
 * @date 2022年06月30日 20:55
 * @desc
 */
public class AtomicIntegerTest {

    public static void main(String[] args) {
        AtomicInteger i = new AtomicInteger(10);
        // 获取并自增（i = 10, 结果 i = 11, 返回 10），类似于 i++
        System.out.println(i.getAndIncrement()); // 10
        // 自增并获取（i = 11, 结果 i = 12, 返回 12），类似于 ++i
        System.out.println(i.incrementAndGet()); // 12
        // 自减并获取（i = 12, 结果 i = 11, 返回 11），类似于 --i
        System.out.println(i.decrementAndGet());  // 11
        // 获取并自减（i = 11, 结果 i = 10, 返回 11），类似于 i--
        System.out.println(i.getAndDecrement());  // 11
        // 获取并加值（i = 10, 结果 i = 15, 返回 10）
        System.out.println(i.getAndAdd(5));  // 10
        // 加值并获取（i = 15, 结果 i = 10, 返回 10）
        System.out.println(i.addAndGet(-5));  // 10
        // 获取并更新（i = 10, p 为 i 的当前值, 结果 i = 8, 返回 10）
        // 其中函数中的操作能保证原子，但函数需要无副作用
        System.out.println(i.getAndUpdate(p -> p - 2)); // 10
        // 更新并获取（i = 8, p 为 i 的当前值, 结果 i = 10, 返回 10）
        // 其中函数中的操作能保证原子，但函数需要无副作用
        System.out.println(i.updateAndGet(p -> p + 2));  // 10
        // 获取并计算（i = 10, p 为 i 的当前值, x 为参数1即10, 结果 i = 20, 返回 10）
        // 其中函数中的操作能保证原子，但函数需要无副作用
        // getAndUpdate 如果在 lambda 中引用了外部的局部变量，要保证该局部变量是 final 的
        // getAndAccumulate 可以通过 参数1 来引用外部的局部变量，但因为其不在 lambda 中因此不必是 final
        System.out.println(i.getAndAccumulate(10, (p, x) -> p + x)); // 10
        // 计算并获取（i = 20, p 为 i 的当前值, x 为参数1即-10, 结果 i = 10, 返回 10）
        // 其中函数中的操作能保证原子，但函数需要无副作用
        System.out.println(i.accumulateAndGet(-10, (p, x) -> p + x));
    }

    public static int updateAndGet(AtomicInteger i, IntUnaryOperator operator) {
        while (true) {
            int prev = i.get();
            int next = operator.applyAsInt(prev);
            if (i.compareAndSet(prev, next)) {
                return next;
            }
        }
    }

}
